#[macro_use]
extern crate log;

use std::time;

fn main() {
    if let Err(err) = logger_init() {
        println!("logger init err:{}", err);
    }

    logger_test();
}

struct LogTargetMap {}

impl honeybee_log::TargetMapping for LogTargetMap {
    fn map(name: &str) -> honeybee_log::TargetIndex {
        match name {
            "score" => honeybee_log::TargetIndex::T1,
            "object" => honeybee_log::TargetIndex::T2,
            _ => honeybee_log::TargetIndex::T0,
        }
    }
}

fn logger_init() -> Result<(), Box<dyn std::error::Error>> {
    let default_log = honeybee_log::name(module_path!())
        .level("debug")?
        /*
        .appender(
            honeybee_log::Appender::new_file_appender("./log/default.log")?
                .with_format(|file, record| {
                    file.write_all(record.content.as_bytes())?;
                    Ok(())
                })
                .build(),
        )
        */
        .appender(
            honeybee_log::Appender::new_file_mmap_appender("./log/default.log", 4096)?.build(),
        )
        .appender(honeybee_log::Appender::new_console_appender().build())
        .build();

    let score_log = honeybee_log::name("score")
        .level("trace")?
        .appender(honeybee_log::Appender::new_file_appender("./log/score.log")?.build())
        .build();

    let object_log = honeybee_log::name("object")
        .level("info")?
        .appender(honeybee_log::Appender::new_file_appender("./log/object.log")?.build())
        .appender(honeybee_log::Appender::new_console_appender().build())
        .build();

    honeybee_log::LogBuilder::<LogTargetMap>::new()
        .add_logger(default_log)
        .add_logger(score_log)
        .add_logger(object_log)
        .init()
}

fn logger_test() {
    SCOPE_TIME_MONITOR!("log record 1000000");
    honeybee_log::Controller::<LogTargetMap>::new()
        .remove_appender(module_path!(), "console_appender");
    honeybee_log::Controller::<LogTargetMap>::new().remove_appender("object", "console_appender");
    for _ in 0..1000000 {
        debug!(
            "223456789abcdefghigklmnopqrstuvwxyz - {} - {}",
            "123456789abcdefghigklmnopqrstuvwxyz", 12345678
        );
        /*trace!(
            "223456789abcdefghigklmnopqrstuvwxyz - {} - {}",
            "123456789abcdefghigklmnopqrstuvwxyz",
            12345678
        );*/
        //debug!(target: "score", "score - {} - {}", "123456789abcdefghigklmnopqrstuvwxyz", 12345678);
        //debug!(target: "object", "object - {} - {}", "123456789abcdefghigklmnopqrstuvwxyz", 12345678);
    }

    /*
    use async_std::task;

    let test = task::Builder::new()
        .name("async_log_test".into())
        .spawn(async {
            for _ in 0..100 {
                debug!(
                    "async 223456789abcdefghigklmnopqrstuvwxyz - {} - {}",
                    "123456789abcdefghigklmnopqrstuvwxyz", 12345678
                );
            }
        })
        .unwrap();
    task::block_on(test);
    */

    honeybee_log::Controller::<LogTargetMap>::new().add_appender(
        module_path!(),
        honeybee_log::Appender::new_console_appender().build(),
    );

    log::logger().flush();
}

pub struct ScopeTimeMonitor {
    start: time::Instant,
    msg: String,
    threshold: time::Duration,
}

impl ScopeTimeMonitor {
    pub fn new<T: std::string::ToString>(msg: T, threshold: time::Duration) -> Self {
        Self {
            start: time::Instant::now(),
            msg: msg.to_string(),
            threshold,
        }
    }
}

impl Drop for ScopeTimeMonitor {
    fn drop(&mut self) {
        let elapsed = self.start.elapsed();
        if elapsed >= self.threshold {
            println!("{} 用时: {}(ms)", self.msg, elapsed.as_millis());
        }
    }
}

#[macro_export]
macro_rules! SCOPE_TIME_MONITOR {
    ($msg: expr) => {
        let _t = crate::ScopeTimeMonitor::new($msg, std::time::Duration::from_millis(0));
    };
    ($msg: expr, $threshold: expr) => {
        let _t = crate::ScopeTimeMonitor::new($msg, $threshold);
    };
}
